package classifieurs;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import mainprogram.Statistiques;

import extraction.Categorie;
import extraction.Extraction;
import extraction.Tweet;

import tools.FrenchTokenizer;
import tools.Normalizer;

public class ClassificationIrrelevantBinomiale extends Classification{

	public ClassificationIrrelevantBinomiale(HashMap<String, Categorie> statParClasse) {
		super(statParClasse);
	}

	/**
	 * Maps pour ranger les parametres betas - 1 par catégorie: <mot, parametre> 
	 */	
	public HashMap<String, Float> mapRelevant = new HashMap<String, Float>();
	public HashMap<String, Float> mapIrr = new HashMap<String, Float>();


	/**
	 * comptes pour binomial
	 */
	public void modeleBinomial(){
		//<mot <nbDansPositive, nbDansNegative, nbDansNeutral, nbDansIrrelevant>>
		HashMap<String, ArrayList<Float>> mapBinomial = new HashMap<String, ArrayList<Float>>();

		ArrayList<Float> tabMapBinomial;
		HashMap<String, Integer> hashRelevant = new HashMap<String, Integer>();

		HashMap<String, Integer> hashPos = positive.getMotsTweet();
		HashMap<String, Integer> hashNeg = negative.getMotsTweet();
		HashMap<String, Integer> hashNeu = neutral.getMotsTweet();
		HashMap<String, Integer> hashIrr = irrelevant.getMotsTweet();

		/*Tous les mots dans mapBinomial avec le tableau correspondant*/
		for(String mot : Extraction.mots){
			tabMapBinomial = new ArrayList<Float>(2);
			if (hashPos.get(mot) == null)
				hashPos.put(mot, 0);
			if (hashNeg.get(mot) == null)
				hashNeg.put(mot, 0);
			if (hashNeu.get(mot) == null)
				hashNeu.put(mot, 0);
			hashRelevant.put(mot, hashPos.get(mot)+hashNeg.get(mot)+hashNeu.get(mot));
			//ajout relevant
			if (hashRelevant.get(mot) == 0)
				tabMapBinomial.add(epsilon);
			else
				tabMapBinomial.add((float)hashRelevant.get(mot));
			//ajout irrelevant
			if (hashIrr.get(mot) == null)
				tabMapBinomial.add(epsilon);
			else
				tabMapBinomial.add((float)hashIrr.get(mot));
			mapBinomial.put(mot, tabMapBinomial);

		}

		Float betaRelevant;
		Float betaIrr;
		for (Entry<String, ArrayList<Float>> entry : mapBinomial.entrySet()){
			//nbr docs contenant ce mot (dans la classe) sur nb tot docs dans classe
			betaRelevant = entry.getValue().get(0)/ (positive.getListeTweet().size() + negative.getListeTweet().size() + neutral.getListeTweet().size());
			betaIrr = entry.getValue().get(1)/ irrelevant.getListeTweet().size();
			mapRelevant.put(entry.getKey(), betaRelevant );
			mapIrr.put(entry.getKey(), betaIrr );
		}
	}


	/**
	 * Calcul pourcentage erreur validation croisée pour 1 test
	 * parmis découpe en 10 parties
	 * 1 = test, 9=apprentissage
	 * Répétition 10 fois en changeant bloc test
	 * @return pourcentage erreur pour le test
	 */
	public float validationCroisee(){
		ArrayList<Tweet> listeTweet = test_positive.getListeTweet();
		listeTweet.addAll(test_negative.getListeTweet());
		listeTweet.addAll(test_neutral.getListeTweet());
		listeTweet.addAll(test_irrelevant.getListeTweet());
		
		HashMap<String, Integer> err_relevant = new HashMap<String, Integer>();
		HashMap<String, Integer> err_irrelevant = new HashMap<String, Integer>();
		int ok=0;
		int nonok=0;
		for (Tweet t : listeTweet){
			float vraisRelevant = calculVraisemblanceBinomial(t, mapRelevant);
			float vraisIrr = calculVraisemblanceBinomial(t, mapIrr);
			float max = (vraisRelevant > vraisIrr) ? vraisRelevant : vraisIrr;
			String max_string = null;
			String sentiment = "";
			//System.out.println("valeurs vraisemblance : relevant : "+vraisRelevant+" irr : "+vraisIrr);
		
			if (max==vraisRelevant) max_string = "relevant";
			else if (max==vraisIrr) {
				max_string = "irrelevant";
			}

			if (t.getSentiment().equals("test_irrelevant"))
				sentiment = "irrelevant";
			else 
				sentiment = "relevant";

			if(sentiment.equals(max_string)){//t.getSentiment().equals("test_"+max_string)){
				ok++;
			}
			else{
				nonok++;
			}
			
			if (max_string.equals("relevant")){
				if (err_relevant.get(t.getSentiment()) == null)
					err_relevant.put(t.getSentiment(), 1);
				else 
					err_relevant.put(t.getSentiment(), err_relevant.get(t.getSentiment())+1);
			}
			else if (max_string.equals("irrelevant")){
				if (err_irrelevant.get(t.getSentiment()) == null)
					err_irrelevant.put(t.getSentiment(), 1);
				else
					err_irrelevant.put(t.getSentiment(), err_irrelevant.get(t.getSentiment())+1);
			}
		}
		System.out.println("ok="+ok+" et nonok="+nonok+" --> pourcentage nonok : "+ ((float)nonok/(ok+nonok)));
		System.out.println("erreurs matrice : ");
		System.out.println("relevant : "+err_relevant);
		System.out.println("irrelevant : "+err_irrelevant);

		return ((float)nonok/(ok+nonok));
		//return err_relevant;
	}

	/**
	 * decide si tweet relevant ou irrelevant
	 * @param listeTweet
	 */
	public void decisionRelevantIrrelevant(){
		ArrayList<Tweet> listeTweet = test_positive.getListeTweet();
		listeTweet.addAll(test_negative.getListeTweet());
		listeTweet.addAll(test_neutral.getListeTweet());
		listeTweet.addAll(test_irrelevant.getListeTweet());

		for (Tweet t : listeTweet){
			float vraisRelevant = calculVraisemblanceBinomial(t, mapRelevant);
			float vraisIrr = calculVraisemblanceBinomial(t, mapIrr);
			float max = (vraisRelevant > vraisIrr) ? vraisRelevant : vraisIrr;
			String max_string = null;
			if (max==vraisRelevant) max_string = "relevant";
			else if (max==vraisIrr) max_string = "irrelevant";

			t.setSentiment_test(max_string);
		}

	}
	
	/**
	 * decide si tweet relevant ou irrelevant
	 * @param listeTweet
	 */
	public void decision(){
		ArrayList<Tweet> listeTweet = test_polarite.getListeTweet();
		
		for (Tweet t : listeTweet){
			float vraisRelevant = calculVraisemblanceBinomial(t, mapRelevant);
			float vraisIrr = calculVraisemblanceBinomial(t, mapIrr);
			float max = (vraisRelevant > vraisIrr) ? vraisRelevant : vraisIrr;
			String max_string = null;
			if (max==vraisRelevant) max_string = "relevant";
			else if (max==vraisIrr) max_string = "irrelevant";

			t.setSentiment(max_string);
		}

	}

	/**
	 * Calcul vraisemblance pour 1 doc
	 * @param tweet : document considéré
	 * @param mapCategorie : liste des mots du dico pour cette classe avec leurs parametres respectifs
	 * @return inference : <0, plus elle est proche de 0, plus le Tweet est proche de la catégorie concernée
	 */
	public float calculVraisemblanceBinomial (Tweet tweet, HashMap<String, Float> mapCategorie){
		float vraisemblance = 0;
		ArrayList<String> tabMotsDoc = 	tweet.getMotsTweetText();
		//parcour map dico
		for (Entry<String, Float> entry : mapCategorie.entrySet()){
			//mot présent dans doc ?
			if (tabMotsDoc.contains(entry.getKey())){
				//vraisemblance 
				vraisemblance += Math.log(entry.getValue());
			}
			else
				vraisemblance += Math.log(1-entry.getValue());
		}
		return vraisemblance;
	}



	public static void main(String[] args) {
		Statistiques stats = new Statistiques();
		DataClassification d = new DataClassification();
		try {
			//stats.analyseFichier("./train.txt"); //remplit statParClasse (analyse avec extraction)
			//d.mots_significatifs = stats.getMotsMoinsSignificatifs(); //remplit la map mots_significatifs

			//remplissage des map
			d.analyseFichier("./trainMelange.txt");
			Classification cl;
			HashMap<String, Integer> err = new HashMap<String, Integer>();
			float err_neg = 0;
			float err_pos = 0;
			float err_neu = 0;
			float err_irr = 0;
			
			//float err1 = 0;
		for (int i =0; i<10; i++){
				cl = new ClassificationIrrelevantBinomiale(d.mapStatParClass.get(i)); //bloc test  = 0
				((ClassificationIrrelevantBinomiale) cl).modeleBinomial(); 
				((ClassificationIrrelevantBinomiale) cl).decisionRelevantIrrelevant();
				cl = new Binomiale_3pol(d.mapStatParClass.get(i));
				((Binomiale_3pol) cl).modeleBinomial();
				((Binomiale_3pol) cl).decisionPolarite();
//				if (err.get("test_negative") != null)
//					err_neg += err.get("test_negative");
//				if (err.get("test_positive") != null)
//					err_pos += err.get("test_positive");
//				if (err.get("test_neutral") != null)
//					err_neu += err.get("test_neutral");
//				if (err.get("test_irrelevant") != null)
//					err_irr += err.get("test_irrelevant");
			}

			
//			System.out.println("erreur moyenne considéré pos: "+ (float)err_pos/10);
//			System.out.println("erreur moyenne considéré neg : "+ (float)err_neg/10);
//			System.out.println("erreur moyenne considéré neu : "+ (float)err_neu/10);
//			System.out.println("erreur moyenne considéré irr : "+ (float)err_irr/10);
			
			//System.out.println("erreur moyenne : "+ (float)err1/10);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
